package com.gao.web.filter;

import com.gao.manager.jwt.JwtKeeper;
import com.gao.util.JwtUtils;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author gao
 * @time 2022/11/05 11:56:21
 */
@RequiredArgsConstructor
@Component
public class JwtFilter extends OncePerRequestFilter {

    @NonNull
    private UserDetailsService userDetailsService;

    @NonNull
    private JwtKeeper jwtKeeper;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 判断请求中是否携带jwt，如果没有携带则直接放行给后续过滤器处理
        String jwt = request.getHeader("Authorization");
        if (jwt == null) {
            filterChain.doFilter(request, response);
            return;
        }

        // 判断JwtKeeper是否包含该jwt，如果没有包含则直接放行
        if (!jwtKeeper.contains(jwt)) {
            filterChain.doFilter(request, response);
            return;
        }

        // 判断request中携带的jwt是否合法，如果不合法则直接放行给后续过滤器处理
        boolean bb = JwtUtils.verifyToken(jwt);
        if (!bb) {
            filterChain.doFilter(request, response);
            return;
        }

        UserDetails userDetails = obtainUserDetailsByJwt(jwt);

        // 让当前用户直接成功已认证的状态
        authentictedCurrentUser(userDetails);

        // 放行
        filterChain.doFilter(request, response);
    }

    private UserDetails obtainUserDetailsByJwt(String jwt) {
        // 从jwt中获取出用户名，然后根据用户名查询出用户权限信息，并存入SecurityContextHolder中
        String username = JwtUtils.getUsername(jwt);
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        return userDetails;
    }

    private void authentictedCurrentUser(UserDetails userDetails) {
        // 调用三个参数的UsernamePasswordAuthenticationToken构造器，在该构造器中会设置用户的认证状态为已认证
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }

}
